#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <limits> // 新增：包含 <limits> 头文件
#include "Common.hpp"
#include "Protocol.hpp"//形成约定

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        return 1;
    }
    std::string server_ip = argv[1];
    int server_port = std::stoi(argv[2]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // tcp的套接字
    if (sockfd < 0)
    {
        std::cout << "创建套接字失败 error" << std::endl;
        return 2;
    }

    // 客户端吧需要显示的bind会在调用connect时自动随机绑定。
    // tcp是面向链接的

    sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());

    int n = ::connect(sockfd, CONV(&server_addr), sizeof(server_addr));
    if (n < 0)
    {
        std::cout << "连接服务器失败 error" << std::endl;
        Die(CONNECT_ERR);
    }

    // 读写消息
    std::string input_msg;
    while (true)
    {
        int x,y;
        char oper;
        //并不安全的输入方式，此时在x或y中输入字符就会循环打印input x:input y:input oper:0[3]
        // std::cout<<"input x:";
        // std::cin>>x;
        // std::cout<<"input y:";
        // std::cin>>y;
        // std::cout<<"input oper:";
        // std::cin>>oper;

        //下面是一种安全的考虑非法输入值的情况下的代码
        std::cout << "input x:";
        if (!(std::cin >> x))
        {
            std::cout << "输入错误，请输入数字！" << std::endl;
            std::cin.clear(); // 清除错误标志
            // 清空输入缓冲区（直到换行符）
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue; // 重新循环，等待正确输入
        }

        // 读取y，并处理输入错误
        std::cout << "input y:";
        if (!(std::cin >> y))
        {
            std::cout << "输入错误，请输入数字！" << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }

        // 读取oper（简单处理，可根据需求扩展）
        std::cout << "input oper:";
        if (!(std::cin >> oper))
        {
            std::cout << "输入错误，请输入操作符！" << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }

        Request req(x,y,oper);

        //1.序列化
        req.Serialize(input_msg);
        // std::cout<<"序列化成功"<<std::endl;
        // std::cout<<"input_msg:"<<input_msg<<std::endl;
        //2.添加报头
        Encode(input_msg);
        // std::cout<<"添加报头成功"<<std::endl;
        // std::cout<<"input_msg:"<<input_msg<<std::endl;
        //3.发送
        int n=::write(sockfd, input_msg.c_str(), input_msg.size());
        if(n>0)
        {
            //4.获得应答
            // std::cout<<"发送成功"<<std::endl;
            char inbuffer[1024];
            int m=::read(sockfd,inbuffer,sizeof(inbuffer));
            if(m>0)
            {
                // std::cout<<"收到应答"<<std::endl;
                inbuffer[m]='\0';
                std::string package = inbuffer;//TODO
                std::string content;
                //这里认为读到的应答是完整的--暂定应该要while去判断这里认为就是完整的。
                //下面代码和服务器的一样
                Decode(package,&content);

                //5.反序列化
                Response resp;
                resp.Deserialize(content);

                //6.得到一个结构化数据
                std::cout<<resp.Result()<<"["<<resp.Code()<<"]"<<std::endl;
            }
            else 
            {
                std::cout<<"没有收到应答"<<std::endl;
                break;
            }
        }
        else 
        {
            std::cout<<"没有去写消息"<<std::endl;
            break;
        }
    }
    ::close(sockfd);
    return 0;
}